package map.location

import android.Manifest
import android.content.Intent
import android.location.Location
import android.location.LocationListener
import android.os.CancellationSignal
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
import com.baidu.mapapi.map.MyLocationConfiguration
import com.baidu.mapapi.map.MyLocationConfiguration.LocationMode
import com.baidu.mapapi.map.MyLocationData
import com.baidu.mapapi.model.LatLng
import com.zjw.zy.base.publisher.DefaultPublisher
import com.zjw.zy.base.publisher.IPublisher
import com.zjw.zy.smi.JustWithIt
import com.zjw.zy.utils.AppUtils
import com.zjw.zy.utils.PermissionUtils
import com.zjw.zy.utils.taskpool.BackGroundExecutor
import com.zjw.zy.utils.taskpool.TaskPool
import map.MapBaseManager
import map.ext.map

class LocationManager : MapBaseManager() {


    companion object {
        private const val TAG = "LocationManager"

        /**请求一次定位*/
        @JvmStatic
        @SuppressWarnings("all")
        fun requestOnceLocation(call: JustWithIt<LatLng>) {
            AppUtils.getApp().getSystemService(android.location.LocationManager::class.java)
                .let { locationManager ->
                    var locationProvider = ""
                    val providers = locationManager.getProviders(true)
                    locationProvider =
                        if (providers.contains(android.location.LocationManager.NETWORK_PROVIDER)) {
                            android.location.LocationManager.NETWORK_PROVIDER
                        } else if (providers.contains(android.location.LocationManager.GPS_PROVIDER)) {
                            android.location.LocationManager.GPS_PROVIDER
                        } else {
                            return
                        }
                    if (PermissionUtils.accessPermissions(
                            arrayOf(
                                Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION
                            )
                        )
                    ) {
                        val location = locationManager.getLastKnownLocation(locationProvider)
                        if (location != null) {
                            call.onWith(LatLng(location.latitude, location.longitude))
                            return
                        }
                        locationManager.requestLocationUpdates(
                            locationProvider,
                            10L,
                            10F,
                            object : LocationListener {
                                override fun onLocationChanged(location: Location) {
                                    call.onWith(LatLng(location.latitude, location.longitude))
                                    locationManager.removeUpdates(this)
                                }
                            })

                        return
                    }
                    PermissionUtils.toastNotAccessPermission()
                }
        }
    }

    private var mLocationClient: LocationClient? = null
    private var mCurrentLocation: MyLocationData? = null
    private val mCurrentLocationPublisher: IPublisher<JustWithIt<LatLng>> =
        DefaultPublisher()

    private val mCurrentLocationLock = Any()

    override fun onCreate() {
        initLocation()
    }

    override fun onDestroy() {
        destroyLocation()
    }

    fun requestCurrentLocationByCall(call: JustWithIt<LatLng>) {
        mCurrentLocationPublisher.subscribe(object : JustWithIt<LatLng> {
            override fun onWith(obj: LatLng?) {
                call.onWith(obj)
                mCurrentLocationPublisher.unsubscribe(this)
            }
        })
    }

    private fun initLocation(listener: BDAbstractLocationListener = MyLocationListener()) {
        mLocationClient = LocationClient(AppUtils.getApp())

        LocationClientOption().apply {
            //打开gps
            this.openGps = true
            //坐标类型
            this.coorType = "bd09ll"
            this.setScanSpan(1000)
            mLocationClient?.locOption = this
        }
        mLocationClient?.registerLocationListener(listener)
        mLocationClient?.start()
    }

    private fun destroyLocation() {
        mLocationClient?.stop()
        mLocationClient = null
        AppUtils.getApp().stopService(Intent("com.baidu.location.f").apply {
            `package` = AppUtils.getMapActivity().packageName
        })
    }

    private inner class MyLocationListener : BDAbstractLocationListener() {
        override fun onReceiveLocation(location: BDLocation) {
            synchronized(mCurrentLocationLock) {
                mCurrentLocation = MyLocationData.Builder()
                    .accuracy(location.radius)
                    .direction(location.direction)
                    .latitude(location.latitude)
                    .longitude(location.longitude).build()

                map().setMyLocationData(mCurrentLocation)

                TaskPool.concurrent().post {
                    mCurrentLocationPublisher.publish {
                        val latitude: Double = mCurrentLocation?.latitude ?: 0.0
                        val longitude: Double = mCurrentLocation?.longitude ?: 0.0
                        it.onWith(LatLng(latitude, longitude))
                    }
                }
            }
        }
    }


    fun locationMode(locationMode: LocationMode = LocationMode.NORMAL) {
        map().setMyLocationConfiguration(
            MyLocationConfiguration(
                locationMode,
                false,
                null
            )
        )
    }

    //所处位置
    fun locationLatLng(): LatLng {
        synchronized(mCurrentLocationLock) {
            val latitude: Double = mCurrentLocation?.latitude ?: 0.0
            val longitude: Double = mCurrentLocation?.longitude ?: 0.0
            return LatLng(latitude, longitude)
        }
    }

    //所处位置
    fun locationInfo(): MyLocationData {
        synchronized(mCurrentLocationLock) {
            return MyLocationData.Builder().apply {
                latitude(mCurrentLocation?.latitude ?: 0.0)
                longitude(mCurrentLocation?.longitude ?: 0.0)
                speed(mCurrentLocation?.speed ?: 0.0f)
                direction(mCurrentLocation?.direction ?: 0.0f)
                accuracy(mCurrentLocation?.accuracy ?: 0.0f)
                satellitesNum(mCurrentLocation?.satellitesNum ?: 0)
            }.build()
        }
    }

}